-- LoginM
-- created by panyl
-- 登陆验证模块

module("LoginM", package.seeall);

-- 内部函数声明
local autoLogin;
local onConnected;
local onDisconnect;
local onConnectTimeout;
local needSync;
local nextFloor;
local onMsgDone;
local showDisconnectTip;

local login_stage = 0;

-- 只连一次的标记
local connectOnlyOnce = false;

-- 模块初始化操作
function init()
    EventMgr.removeAll("LoginM");
    EventMgr.register("LoginM", event.MESSAGE_DONE, onMsgDone)

    -- 注册连接断开事件
    EventMgr.register("LoginM", event.NETWORK_DISCONNECTED, onDisconnect);

    -- 网络连接事件
    EventMgr.register("LoginM", event.NETWORK_CONNECTED, onConnected);

    -- 连接超时回调
    EventMgr.register("LoginM", event.NETWORK_CONNECT_TIMEOUT, onConnectTimeout);

    -- 自动登陆
    autoLogin = false;

    -- 是否需要同步数据
    needSync = false;
    nextFloor = false;

    -- 是否显示断线重连提示
    showDisconnectTip = true;
end

-- 设置自动登陆
function setAutoLogin()
    autoLogin = true;
end

-- 获取自动登陆
function getAutoLogin()
    return autoLogin;
end

-- 设置登录阶段
function set_login_stage(s)
    login_stage = s;
    trace("LoginM", "登录阶段切换为：%s", tostring(s));
    EventMgr.fire(event.LOGIN_STAGE_CHANGE, s);
end

-- 获取客户端版本号
function getClientVersion(onlyRealVersion)
    print("getClientVersion CLIENT_VERSION:"..CLIENT_VERSION);

    local clientVersion;

    if onlyRealVersion then
        local list = string.explode(CLIENT_VERSION, "-");
        return list[1];
    end

    if DEBUG_MODE == 1 then
        clientVersion = CLIENT_VERSION;
    else
        local list = string.explode(CLIENT_VERSION, "-");
        if #list == 1 then
            clientVersion = list[1];
        elseif #list == 2 then
            clientVersion = list[2];
        end
    end

    return clientVersion;
end

-- 检查是否需要重新下载资源
-- 当dislist中设置了upgrade_by_server_version=1，在登陆前
-- 根据玩家所在gs的支持版本号，检查是否需要对服务器资源进行重新更新。
function checkResDownload(serverSupportVersion, callback)
    if _G["dislist"] == nil or _G["dislist"]["upgrade_by_server_version"] ~= 1 then
        -- 没有配置dislist或者字段upgrade_by_server_version不为1，直接进行后续流程
        callback();
        return;
    end

    local  clientVersion = getClientVersion(true);

    if clientVersion == serverSupportVersion then
		-- 版本号最新，不需要下载，直接进行后续流程
        callback();
        return;
    end

    EventMgr.fire(event.UPGRADE_BY_SERVER_VER, { ["ver"] = serverSupportVersion, ["callback"] = callback });
end

-- 消息处理完成回调
onMsgDone = function(para)
    -- 关注MSG_AUTH_ACCOUNT_RESULT消息
    if para[1] == "MSG_AUTH_ACCOUNT_RESULT" then
        onTakeServerTicket(para);
    end
end

-- 获取服务器门票成功回调
onTakeServerTicket = function(para)
    if para[1] ~= "MSG_AUTH_ACCOUNT_RESULT" then
        return
    end

    -- 不管结果如何都先关闭和aaa的链接
    Socket.disconnect()

    local args = para[2];

    if args.result ~= 1 then
        return
    end

    -- 获取原始账号
    local origAccount = args.para.account;
    if origAccount then
        local index = string.find(origAccount, "_");
        local tempAccount = string.sub(origAccount, index + 1, string.len(origAccount));

        if _G.aaaAccountInfo.account ~= tempAccount then
            -- 这种情况应该是绑定了账号
            -- 使用原始账号登录
            trace("LoginM", "(%s)绑定的原始账号为：%s", _G.aaaAccountInfo.account, origAccount);
            _G.aaaAccountInfo.account = tempAccount;
        end

        -- 将原始账号记录下来
        AccountM.setGamingAccount(origAccount);
    end

    local account = _G.aaaAccountInfo.account
    local ip      = _G.aaaAccountInfo.server_ip
    local port    = _G.aaaAccountInfo.server_port

    Operation.cmd_login(account, ip, port)
end

-- 重连服务器
function reConnect()
    -- 服务器ip、端口
    local ip   = _G.ip;
    local port = _G.port;

    if not ip or not port then
        trace("LoginM", "取不到服务器ip端口。");
        return;
    end

    trace("LoginM", "account: %s, ip: %s, port: %s。", _G.account, _G.ip, _G.port);

    -- 连接服务器
    Socket.connect(ip, port);

    -- 处理完成
    return true;
end

-- 尝试重连一次
function reConnectOnce()
    trace("loginM", "尝试重连一次");
    reConnect();
    connectOnlyOnce = true;
end


-- 连接服务器成功后的处理
onConnected = function()
    -- 如果不是在游戏中
    if not ME.isInGame then
        return;
    end

-- SLIMEC-3321 移到msg_relogin消息到达后才去除
-- by cheny3
--    if not needSync and not nextFloor then
--        closeCommunicatingForm();
--    end

    -- 重新登录
    Operation.cmd_relogin();
end

-- 同步数据
function syncData()
    if needSync then
        -- 同步
        DungeonM.sync();
    elseif nextFloor then
        -- 进入下一层
        DungeonM.nextFloor(true);
    end
    nextFloor = false;
    needSync = false;
end

-- 是否需要执行进入下一层
function dungeonNextFloor(flag)
    nextFloor = flag;
end

-- 是否需要同步数据
function needSyncFlag(flag)
    needSync = flag;
end

-- 设置是否显示一般断线重连
function setShowDisconnectTip(flag)
    showDisconnectTip = flag;
end

-- 静默重连
function quiteReconnect()
    trace("LoginM", "quiteReconnect");

    -- 显示重连中
    showCommunicatingForm();

    -- 重连
    reConnect();
end

function tryReconnect(title, msg)
    if not showDisconnectTip then
        -- 设置了不显示
        return;
    end

	connectOnlyOnce = false;

    if isVerifyClient() then
        reConnect();
        return;
    end

    -- 提示重连
    local function onOK()
        quiteReconnect();
        return;
    end

    if appEnterForegroundTime ~= nil and os.time() - appEnterForegroundTime < 2 then
        -- 视为切换程序前后台导致的断线，直接静默重连
        onOK();
    else
        confirm2(CONFIRM_TYPE_OK, title, msg, onOK, nil, getLocStr("btn_text_reconnect"))
        local uiDialog = UIMgr.getCurrentScene():getCurrentDialog();
        uiDialog:hideBackBtn();
    end
end

-- 连接断开回调
onDisconnect = function()
    -- 如果不是在游戏中
    if not ME.isInGame then
        return;
    end

    -- 处于迷宫中，发现连接断开不马上提示玩家，等到点击下一层后才处理
    if not isVerifyClient()
        and DungeonM.getState() == DUNGEON_GAMING
        and UIMgr.getCurrentScene():isOpen("UIDungeonMain") then

        if showDisconnectTip and appEnterForegroundTime ~= nil and os.time() - appEnterForegroundTime < 2 then
            -- 尝试偷偷连一次，为了防止已经掉线超过半小时而没有提示玩家，导致玩家该关卡白打
            reConnectOnce();
        end
        return;
    end

    tryReconnect(getLocStr("warning_title"), getLocStr("disconnect_tip"));
end

-- 连接超时
onConnectTimeout = function()
    if connectOnlyOnce then
        connectOnlyOnce = false;
        return;
    end

    local msg = getLocStr("connect_timeout_tip") .. getLocStr("error_code") .. tostring(login_stage);
    tryReconnect(getLocStr("connect_timeout_title"), msg);
end

-- 检查网络
function checkNetwork()
    if not Socket.isConnected() then
        EventMgr.fire(event.NETWORK_DISCONNECTED);
    end
end

function clearScheduler()
    -- 移除事件关注
    EventMgr.remove("LoginM", event.NETWORK_CONNECTED)
    EventMgr.remove("LoginM", event.NETWORK_DISCONNECTED)
end

-- 游客登录
function tryGuestLogin()
    -- 目前仅开放了ios平台的游客登录
    if isIosPlatform() or isAndroidPlatform() then
        -- 获取广告标示符
        local idfa = SdkMgr.getIdfa();

        if idfa == IDFA_NULL_VALUE then
            -- idfa获取失败
            EventMgr.fire(event.GET_IDFA_FAIL);
            return false;
        end

        -- 将游戏别名、idfa及秘钥拼接起来，然后用md5加密
        local account = string.format("%s_%s_%s", GAME_ALIAS, idfa, GUEST_LOGIN_SECRET);
        account = cc.MD5:getMD5(account);

        trace("LoginM", "游客请求登录游戏，idfa = %s, account = %s", idfa, account);

        local userName = account;
        local password = "";
        local extra    = {
            ["3rdplatform"] = getGuestChannelName(),  -- 采用游客模式登录
            ["idfa"] = idfa,
        };

        EventMgr.fire(event.TRY_GUEST_LOGIN);

        assert(type(CC_IP)          == 'string', "必须配置 CC_IP");
        assert(type(CC_PORT)        == 'string', "必须配置 CC_PORT");
        assert(type(SUPPORT_VERSION) == 'string', "必须配置 SUPPORT_VERSION");

        Operation.cmd_login_cc(userName, password, CC_IP, CC_PORT, SUPPORT_VERSION, extra);

        -- 记录最近一次使用的方式为游客登录
        setLastAccountChannel(getGuestChannelName());

        return true;
    end

    return false;
end





